﻿package code {
	import flash.display.Sprite;
	import flash.events.*;
	import flash.utils.getTimer;
	
	// creates the web
	public class Web extends Sprite{
		
		private var sidesPer, times, originalRadius:int; // sidesPer- the number of sides to the web; times- number of levels to have via recursion; original radius- size of web to start at
		private var previousTime, currentTime:Number;  // the time of last update and time of this update
		public var webVertices, webWires:Array; // web vertices- array of all the vertices in the web; web wires- array of all the wires in the web
		public var tempVert:Vertex;  // tempVert- the current vertex being dragged
		
		public function Web(sidesPer:int, times:int, radius:int) {
			webVertices = new Array();
			webWires = new Array();
			this.sidesPer = sidesPer;
			this.times = times;
			this.originalRadius = radius;
			init();
		}
		
		public function init(){
			webVertices.push(new Vertex(1280 / 2, 720 / 2, 0, 5));  // draws at center of the screen
			tempVert = new Vertex(0, 0, 0, 0); // initializes vertices so that there is no null reference exception
			previousTime = 0;
			createNodes(times, sidesPer, webVertices, originalRadius, new Vertex(1280 / 2, 720 / 2, 0, 5)); // creates a web of vertices recursively
			createWires();	// creates the wires attached to the nodes
			setUpVertexLists();	// sets up the vertex lists to have information about the wires that are attached to them
			drawWeb(); // draws the web on the screen
			processVertices(); // checks all the vertices
			addEventListener(Event.ENTER_FRAME, update);
		}
		
		// generates all of the nodes recursively.  Number of times to recurse, sides per web, vertices of the array, radius of the web, and the start vertex for the web
		public function createNodes(numberOfTimes:int, sidesPer:int, vertices:Array, radius:int, startVert:Vertex){
			if(numberOfTimes > 0){  // recurses until it should no longer recurse
				var theta = (2 * Math.PI) / sidesPer;  // generates the vertices for each side
				for(var i:int = 0; i < sidesPer; i++){
					var tempX = radius * Math.cos(i * theta) + startVert.x;  // creates it from around a point by the radius, similar to polygon generation
					var tempY = radius * Math.sin(i * theta) + startVert.y;
					var tempVert = new Vertex(tempX, tempY, i, numberOfTimes);
					webVertices.push(tempVert);
				}
				createNodes(numberOfTimes - 1, sidesPer, vertices, originalRadius + radius, startVert);
			}
		}
		
		// creates the wires between the vertices
		public function createWires(){
			var lastVertex:Vertex = webVertices[0];  // the last vertex accessed
			var lastFirstVertex:Vertex = webVertices[1]; // the last vertex that is the first vertex for the list
			var vertArray:Array = new Array();  // temporary array of verticse
			
			for(var j:int = 0; j < sidesPer; j++){  // sets up an array for each side
				vertArray.push(new Array());
			}
			
			for(var i:int = 0; i < webVertices.length; i++){
				if(lastVertex.level == webVertices[i].level){
					if(lastVertex.level == times){ // special if goes from center
						webWires.push(new Wire(lastVertex, webVertices[0]));
					}
					webWires.push(new Wire(lastVertex, webVertices[i]));
				}
				else{
					webWires.push(new Wire(lastVertex, lastFirstVertex)); // connects the final to the first for each side
					lastFirstVertex = webVertices[i];
				}
				
				vertArray[i % sidesPer].push(webVertices[i]);  // pushes vertices depending on their angle using mod
				
				lastVertex = webVertices[i];
			}

			webWires.push(new Wire(lastVertex, lastFirstVertex));  
			for each(var arr:Array in vertArray){  // connects all of the vertical nodes
				graphics.moveTo(arr[0].x, arr[0].y);
				var lastVert = arr[0];  // gets each one of the vertice on the list
				for each(var vert:Vertex in arr){
					webWires.push(new Wire(lastVert, vert));
					lastVert = vert;
				}
			}
		}
		
		// sets up the list of vertices to know about the wires they are on
		public function setUpVertexLists(){
			for each(var vertex in webVertices){
				for each(var wire:Wire in webWires){
					if(wire.a == vertex){
						vertex.addWire(wire);
					}
					else if(wire.b == vertex){
						vertex.addWire(wire);
					}
				}
			}
		}
		
		/// draws the wires of the web by adding them
		public function drawWeb(){
			for each(var wire:Wire in webWires){
				addChild(wire);
			}
		}
		
		// processes all of the vertices by adding event listeners to them, unless they are the last one
		public function processVertices(){
			for each(var vert:Vertex in webVertices){
				if(vert.level != 1){  // if the level is not the last in the web, it will add event listeners for it to be moved
					vert.addEventListener(MouseEvent.MOUSE_DOWN, onpress);
					vert.addEventListener(MouseEvent.MOUSE_UP, onrelease);
				}
				addChild(vert);
			}
		}
		
		// main update method
		public function update(e:Event){
			// time stuff
			currentTime = getTimer();  // gets currentTime
			var timeDif = currentTime - previousTime;  // to use getTime
			timeDif /= 100;  
			previousTime = currentTime;
			
			updateVertices(timeDif);  // updates vertices position
			updateWires(); // updates the wires location based on vertex changes

		}
		
		// updates each vertex for spring stuff
		public function updateVertices(timeDif:Number){
			for each(var v:Vertex in webVertices){
				v.checkSprings(timeDif);
			}
		}
		
		
		// updates the wires location
		public function updateWires(){
			for each(var w:Wire in webWires){
				for each(var v:Vertex in webVertices){
					if(w.a == v){
						w.update(v, w.b);
					}
				}
			}
			
		}
		
		// Only drag one ball at a time: -- borrowed from schwartz
		private function onpress(event:MouseEvent):void {
			event.target.startDrag();
			tempVert = (event.target as Vertex);
			tempVert.alreadyChecked = true;  // makes it so that it won't start adjusting tempvert while being dragged
		}
		
		// Stop dragging when mouse released:-- borrowed from schwartz
		private function onrelease(event:MouseEvent):void {
			event.target.stopDrag();
			tempVert.alreadyChecked = false;
		}
		
		// function for playing web
		public function playWeb(){
			addEventListener(Event.ENTER_FRAME, update);
			for each(var v:Vertex in webVertices){
				if(v.level != 1)  // goes through and removes event listener
					v.addEventListener(MouseEvent.MOUSE_DOWN, onpress);
			}
		}
		
		// function for pausing web
		public function pauseWeb(){
			removeEventListener(Event.ENTER_FRAME, update);
			for each(var v:Vertex in webVertices){
				v.removeEventListener(MouseEvent.MOUSE_DOWN, onpress);
			}
		}
		
		// resets the web to original position
		public function resetWeb(){
			for each(var v:Vertex in webVertices){
				removeChild(v);
			}
			for each(var w:Wire in webWires){
				removeChild(w);
			}
			webVertices = new Array();
			webWires = new Array();
			init();
		}

	}
	
}
